package com.iwhalecloud.citybrain.flow.platform.manager.application.service.impl;

import java.util.Objects;

import com.iwhalecloud.citybrain.flow.platform.manager.application.common.enums.ProcessInstanceLinkStatusEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.application.common.enums.ProcessInstanceStatusEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.application.common.event.ProcessInstanceStartEvent;
import com.iwhalecloud.citybrain.flow.platform.manager.application.service.ProcessInstanceStartHandler;
import com.iwhalecloud.citybrain.flow.platform.manager.application.service.SerialNumGenerator;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.FlowModelAppBusi;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.FlowModelProcdef;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.FlowProcessInstanceTraceVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.app.FlowApp;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowAppRepository;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowModelAppBusiRepository;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowModelProcdefRepository;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowProcessInstanceTraceRepository;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.repository.Model;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author lilh
 * @date 2020/12/10 下午2:44
 */
@Service
public class RecordProcessInstanceTraceHandler implements ProcessInstanceStartHandler {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private FlowModelProcdefRepository flowModelProcdefRepository;

    @Autowired
    private FlowModelAppBusiRepository flowModelAppBusiRepository;

    @Autowired
    private FlowProcessInstanceTraceRepository flowProcessInstanceTraceRepository;

    @Autowired
    private SerialNumGenerator serialNumGenerator;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private FlowAppRepository flowAppRepository;

    @Override
    public void handle(ProcessInstanceStartEvent event) {
        FlowProcessInstanceTraceVo trace = new FlowProcessInstanceTraceVo();
        trace.setProcessDefinitionId(event.getProcessDefinition().getId());
        trace.setProcessInstanceId(event.getProcessInstance().getProcessInstanceId());
        trace.setSerialNum(serialNumGenerator.generate());
        trace.setModelName(event.getProcessDefinition().getName());
        trace.setModelKey(event.getProcessDefinition().getKey());
        if (Objects.nonNull(event.getUser())) {
            trace.setStarterId(event.getUser().getUserCode());
            trace.setStarterName(event.getUser().getUserName());
        }
        trace.setStartTime(event.getProcessInstance().getStartTime());
        trace.setStatus(ProcessInstanceStatusEnum.NORMAL.getCode());
        trace.setLinkStatus(event.getIsFromSdkCall() ? ProcessInstanceLinkStatusEnum.START.getCode() : ProcessInstanceLinkStatusEnum.RUNNING.getCode());
        trace.setFlag(0);
        FlowModelProcdef modelProcDef = flowModelProcdefRepository.getModelProcDef(event.getProcessDefinition().getId());
        trace.setVersion(resolveModelVersion(modelProcDef));
        if (Objects.nonNull(modelProcDef)) {
            FlowModelAppBusi appByModelId = flowModelAppBusiRepository.getAppByModelId(modelProcDef.getModelId());
            if (Objects.nonNull(appByModelId)) {
                trace.setAppId(appByModelId.getAppId());
                trace.setAppName(appByModelId.getAppName());
                trace.setBusiId(appByModelId.getBusiId());
                trace.setBusiName(appByModelId.getBusiName());
                trace.setTenantId(resolveTenantIdByAppId(appByModelId.getAppId()));
            }
        } else {
            logger.warn("没有找到模型定义和模型之间的关系");
        }

        flowProcessInstanceTraceRepository.insertProcessInstanceTrace(trace);
    }

    private Integer resolveTenantIdByAppId(Integer appId) {
        FlowApp detail = flowAppRepository.detail(appId);
        if (Objects.nonNull(detail)) {
            return detail.getTenantId();
        }
        return null;
    }

    private Integer resolveModelVersion(FlowModelProcdef modelProcDef) {
        if (Objects.isNull(modelProcDef)) {
            return -1;
        }
        Model model = repositoryService.createModelQuery().modelId(modelProcDef.getModelId()).singleResult();
        if (Objects.nonNull(model)) {
            return model.getVersion();
        }
        return -1;
    }
}
